package com.springboot.es.service;

import com.springboot.es.model.User;
import com.springboot.es.utils.JsonUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author sunxiaotao
 * @version 1.0
 * @date 2021-02-18 3:29 下午
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private RestHighLevelClient client;

    @Override
    public boolean createIndex(String index) throws Exception {
        // 判断索引是否存在
        if(this.existIndex(index)){
            return true;
        }
        // 创建索引
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        return createIndexResponse.isAcknowledged();
    }

    @Override
    public boolean existIndex(String index) throws Exception {
        // 判断索引是否存在
        GetIndexRequest getIndexRequest = new GetIndexRequest(index);
        return client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }

    @Override
    public boolean deleteIndex(String index) throws Exception {
        if (!existIndex(index)) {
            return true;
        }
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    @Override
    public boolean addDocument(String index, String id, String content) throws Exception {
        if (!existIndex(index)) {
            return false;
        }
        IndexRequest request = new IndexRequest(index);
        // 设置超时时间
        request.id(id);
        request.timeout(TimeValue.timeValueSeconds(1));
        // 转换为 json
        request.source(content, XContentType.JSON);

        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        return response.status().getStatus() == 200;
    }

    @Override
    public boolean isExistsDocument(String index, String id) throws Exception {
        GetRequest request = new GetRequest(index, id);
        // 不获取返回的  _source 上下文
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        return client.exists(request, RequestOptions.DEFAULT);
    }

    @Override
    public String getDocument(String index, String id) throws Exception {
        GetRequest request = new GetRequest(index, id);
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        return response.getSourceAsString();
    }

    @Override
    public boolean updateDocument(String index, String id, String content) throws Exception {
        UpdateRequest request = new UpdateRequest(index, "_doc",  id);
        request.timeout(TimeValue.timeValueSeconds(1));
        request.doc(content, XContentType.JSON);
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        return response.status().getStatus() == 200;
    }

    @Override
    public boolean deleteDocument(String index, String id) throws Exception {
        if (!isExistsDocument(index, id)) {
            return true;
        }
        DeleteRequest request = new DeleteRequest(index, id);
        request.timeout(TimeValue.timeValueSeconds(1));
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        return response.status().getStatus() == 200;
    }

    @Override
    public boolean bulkRequest(String index, List<User> contents) throws Exception {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout(TimeValue.timeValueSeconds(1));
        contents.forEach(x -> {
            bulkRequest.add(new IndexRequest(index)
                    .id(x.getId().toString())
                    .source(JsonUtils.objectToJson(x), XContentType.JSON));
        });
        BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        return responses.hasFailures();
    }

    /**
     * 搜索请求
     * @param index
     * @param keyword
     * @return
     * @throws Exception
     */
    @Override
    public List<Map<String, Object>> searchRequest(String index, String keyword) throws Exception {
        // 搜索请求
        SearchRequest searchRequest = StringUtils.hasText(index) ? new SearchRequest(index) : new SearchRequest();

        // 条件构造
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 第几页
        searchSourceBuilder.from(0);
        // 每页多少条
        searchSourceBuilder.size(100);
        // 配置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name").field("description");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        searchSourceBuilder.highlighter(highlightBuilder);

        // 精确查询
//        QueryBuilders.termQuery();
        // 匹配所有
//        QueryBuilders.matchAllQuery();

        // 最细粒度划分：ik_max_word，最粗粒度划分：ik_smart
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery(keyword, "name", "description"));
//        searchSourceBuilder.query(QueryBuilders.matchQuery("content", keyword));
        searchSourceBuilder.timeout(TimeValue.timeValueSeconds(10));

        searchRequest.source(searchSourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);

        List<Map<String, Object>> results = new ArrayList<>();
        for (SearchHit searchHit : response.getHits().getHits()) {
            Map<String, HighlightField> highlightFieldMap = searchHit.getHighlightFields();
            HighlightField title = highlightFieldMap.get("name");
            HighlightField description = highlightFieldMap.get("description");
            // 原来的结果
            Map<String, Object> sourceMap = searchHit.getSourceAsMap();
            // 解析高亮字段，替换原来的字段
            if (title != null) {
                Text[] fragments = title.getFragments();
                StringBuilder n_title = new StringBuilder();
                for (Text text : fragments) {
                    n_title.append(text);
                }
                sourceMap.put("name", n_title.toString());
            }
            if (description != null) {
                Text[] fragments = description.getFragments();
                StringBuilder n_description = new StringBuilder();
                for (Text text : fragments) {
                    n_description.append(text);
                }
                sourceMap.put("description", n_description.toString());
            }

            results.add(sourceMap);
        }

        return results;
    }

    /**
     * 搜索所有的 id
     * @param index
     * @return
     * @throws Exception
     */
    @Override
    public List<Integer> searchAllRequest(String index) throws Exception {
        // 搜索请求
        SearchRequest searchRequest;
        if(!StringUtils.hasText(index)){
            searchRequest = new SearchRequest();
        }else {
            searchRequest = new SearchRequest(index);
        }
        // 条件构造
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 第几页
        searchSourceBuilder.from(0);
        // 每页多少条数据
        searchSourceBuilder.size(1000);
        // 匹配所有
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.timeout(TimeValue.timeValueSeconds(10));

        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        List<Integer> results = new ArrayList<>();
        for (SearchHit searchHit : searchResponse.getHits().getHits()){
            results.add(Integer.valueOf(searchHit.getId()));
        }
        return results;

    }
}
